/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 */

package com.yami.shop.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.dto.OrderRefundDto;
import com.yami.shop.bean.enums.BuyerReasonType;
import com.yami.shop.bean.enums.SendType;
import com.yami.shop.bean.event.SendMessageEvent;
import com.yami.shop.bean.event.SubmitSeckillOrderEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.NotifyTemplateParam;
import com.yami.shop.bean.param.UserTagParam;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.PageAdapter;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.dao.NotifyTemplateMapper;
import com.yami.shop.dao.NotifyTemplateTagMapper;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 *
 *
 * @author lhd
 * @date 2020-07-01 15:44:27
 */
@Service
@AllArgsConstructor
public class NotifyTemplateServiceImpl extends ServiceImpl<NotifyTemplateMapper, NotifyTemplate> implements NotifyTemplateService {

    private final NotifyTemplateMapper notifyTemplateMapper;
    private final NotifyTemplateTagMapper notifyTemplateTagMapper;
    private final ShopDetailService shopDetailService;
    private final UserAddrOrderService userAddrOrderService;
    private final UserService userService;
    private final OrderMapper orderMapper;
    private final ApplicationContext applicationContext;


    /**
     * 消息推送-开团提醒、拼团成功提醒、拼团失败提醒
     * @param order 订单
     * @param groupStart
     */
    @Async
    @Override
    public void sendNotifyOfGroupStart(Order order, SendType groupStart) {
        UserAddrOrder userAddrOrder = userAddrOrderService.getById(order.getAddrOrderId());
        try {
            User user = new User();
            user.setUserMobile(userAddrOrder.getMobile());
            user.setUserId(userAddrOrder.getUserId());
            NotifyTemplateParam param = new NotifyTemplateParam();
            param.setShopId(order.getShopId());
            param.setProdName(order.getProdName());
            param.setSendType(groupStart.getValue());
            param.setPrice(order.getActualTotal());
            param.setUser(user);
            applicationContext.publishEvent(new SendMessageEvent(param));
        }catch (Exception e){
            log.error(groupStart.getDesc() + "：消息推送失败！");
        }

    }

    /**
     * 消息推送
     * @param orders 支付成功
     */
    @Override
    @Async
    public void sendNotifyOfPaySuccess(List<Order> orders) {
        try {
            User user = new User();
            user.setUserMobile(orders.get(0).getReceiverMobile());
            user.setUserId(orders.get(0).getUserId());
            for (Order order : orders) {
                NotifyTemplateParam param = new NotifyTemplateParam();
                param.setShopId(order.getShopId());
                param.setOrderNumber(order.getOrderNumber());
                param.setProdName(order.getProdName());
                param.setSendType(SendType.PAY_SUCCESS.getValue());
                param.setPrice(order.getActualTotal());
                param.setUser(user);
                applicationContext.publishEvent(new SendMessageEvent(param));
            }
        }catch (Exception e){
            log.error(SendType.PAY_SUCCESS.getDesc() + "：消息推送失败！");
        }

    }

    /**
     * 消息推送-申请退款
     * @param order 订单
     * @param orderRefund 退款信息
     */
    @Override
    @Async
    public void sendNotifyOfApplyRefund(Order order, OrderRefund orderRefund) {
        NotifyTemplateParam param = new NotifyTemplateParam();
        ShopDetail shopDetail = shopDetailService.getById(order.getShopId());
        User userDb = userService.getById(order.getUserId());
        try {
            User user = new User();
            user.setUserId(shopDetail.getUserId());
            user.setUserMobile(shopDetail.getReceiveMobile());
            user.setNickName(userDb.getNickName());
            param.setUser(user);

            BuyerReasonType reasonType = BuyerReasonType.instance(Integer.valueOf(orderRefund.getBuyerReason()));
            if (Objects.nonNull(reasonType)) {
                orderRefund.setBuyerReason(I18nMessage.getDbLang() == 0 ? reasonType.getCn() : reasonType.getEn());
            }
            param.setRejectMessage(orderRefund.getBuyerReason());

            param.setRemark(orderRefund.getBuyerDesc());
            param.setPrice(orderRefund.getRefundAmount());
            param.setShopId(order.getShopId());
            param.setOrderNumber(order.getOrderNumber());
            param.setSendType(SendType.LAUNCH_REFUND.getValue());
            applicationContext.publishEvent(new SendMessageEvent(param));
        }catch (Exception e){
            log.error(SendType.LAUNCH_REFUND.getDesc() + "：消息推送失败！");
        }

    }

    /**
     * 消息推送-同意退款、拒绝退款、退款临近超时
     * @param orderRefundDto 退款信息
     * @param sendType 类型
     */
    @Override
    @Async
    public void sendNotifyByRefund(OrderRefundDto orderRefundDto, SendType sendType) {
        try {
            // 消息推送--同意退款
            List<OrderItem> orderItems = orderRefundDto.getOrderItems();
            String orderNumber = orderRefundDto.getOrderNumber();
            StringBuilder prodName = new StringBuilder();
            Order order;
            if(CollectionUtils.isNotEmpty(orderItems)){
                orderNumber = orderItems.get(0).getOrderNumber();
                for (OrderItem orderItem : orderItems) {
                    prodName.append(orderItem.getProdName()).append(StrUtil.COMMA);
                }
                prodName.deleteCharAt(prodName.length() - 1);
                order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber));
            }else {
                order = orderMapper.selectById(orderRefundDto.getOrderId());
            }

            UserAddrOrder userAddrOrder = userAddrOrderService.getById(order.getAddrOrderId());
            ShopDetail shopDetail = shopDetailService.getById(orderRefundDto.getShopId());
            User user = new User();
            user.setUserMobile(userAddrOrder.getMobile());
            user.setUserId(userAddrOrder.getUserId());


            NotifyTemplateParam param = new NotifyTemplateParam();
            param.setUser(user);
            param.setShopId(orderRefundDto.getShopId());
            param.setShopName(shopDetail.getShopName());
            param.setProdName(StrUtil.isNotBlank(prodName.toString())?prodName.toString():order.getProdName());
            param.setSendType(sendType.getValue());
            param.setRejectMessage(orderRefundDto.getRejectMessage());
            param.setRemark(orderRefundDto.getRejectMessage());
            param.setPrice(orderRefundDto.getRefundAmount());
            param.setOrderNumber(order.getOrderNumber());
            // 计算剩余时间
            long hour = DateUtil.between(orderRefundDto.getApplyTime(),new Date(), DateUnit.HOUR);
            param.setHour(Constant.MAX_REFUND_HOUR * 24 - hour);
            applicationContext.publishEvent(new SendMessageEvent(param));
        }catch (Exception e){
            log.error(e.getMessage());
            log.error(sendType.getDesc() + "：消息推送失败！");
        }

    }

    public static void main(String[] args) {
        System.out.println(DateUtil.between(new DateTime("2020-08-10 16:53:02", DatePattern.NORM_DATETIME_PATTERN),new Date(), DateUnit.HOUR));
    }
    /**
     * 消息推送-发货提醒、订单催付提醒
     * @param order 订单
     * @param dvyName
     */
    @Override
    @Async
    public void sendNotifyOfDelivery(Order order, String dvyName, SendType sendType) {
        NotifyTemplateParam param = new NotifyTemplateParam();
        UserAddrOrder userAddrOrder = userAddrOrderService.getById(order.getAddrOrderId());
        try {
            User user = new User();
            User userDb = userService.getById(userAddrOrder.getUserId());
            user.setUserId(userAddrOrder.getUserId());
            user.setUserMobile(userAddrOrder.getMobile());
            user.setNickName(userDb.getNickName());
            param.setUser(user);
            param.setShopId(order.getShopId());
            param.setDvyFlowId(order.getDvyFlowId());
            param.setDvyTime(order.getDvyTime());
            param.setOrderNumber(order.getOrderNumber());
            param.setDvyName(dvyName);
            param.setProdName(order.getProdName());
            param.setCreateTime(order.getCreateTime());
            param.setSendType(sendType.getValue());
            // cancelTime 取消时间处理
            Date cancelTime = null;
            Date createTime = order.getCreateTime();
            if (Objects.equals(2, order.getOrderType())) {
                // 获取秒杀订单的取消订单时间
                Integer maxCancelTime = 0;
                SubmitSeckillOrderEvent event = new SubmitSeckillOrderEvent(order, maxCancelTime);
                applicationContext.publishEvent(event);
                maxCancelTime = event.getMaxCancelTime()<= 0? 30: event.getMaxCancelTime();
                cancelTime = DateUtil.offsetMinute(createTime, maxCancelTime);
            } else {
                cancelTime = DateUtil.offsetMinute(createTime, 30);
            }
            param.setCancelTime(DateUtil.format(cancelTime,"yyyy-MM-dd HH:mm:ss"));
            applicationContext.publishEvent(new SendMessageEvent(param));
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error(sendType.getDesc() + "：消息推送失败！");
        }
    }

    /**
     * 升级提醒
     * @param levelName 会员名称
     * @param userDb 用户信息
     */
    @Override
    @Async
    public void sendNotifyOfLevelUp(String levelName, User userDb) {
        NotifyTemplateParam param = new NotifyTemplateParam();
        try {
            User user = new User();
            user.setUserId(userDb.getUserId());
            user.setUserMobile(userDb.getUserMobile());
            param.setUser(user);
            param.setShopId(1L);
            param.setLevelName(levelName);
            param.setSendType(SendType.MEMBER.getValue());
            applicationContext.publishEvent(new SendMessageEvent(param));
        } catch (Exception e) {
            log.error(SendType.MEMBER.getDesc() + "：消息推送失败！");
        }
    }

    /**
     * 消息推送，核销通知
     * @param stationName 自提点名称
     */
    @Override
    @Async
    public void writeOffOrder(String stationName, Order order) {
        NotifyTemplateParam param = new NotifyTemplateParam();
        try {
            User user = new User();
            User userDb = userService.getById(order.getUserId());
            user.setUserId(order.getUserId());
            user.setUserMobile(order.getReceiverMobile());
            user.setNickName(userDb.getNickName());
            param.setUser(user);
            param.setShopId(order.getShopId());
            param.setOrderNumber(order.getOrderNumber());
            param.setStationName(stationName);
            param.setProdName(order.getProdName());
            param.setPrice(order.getActualTotal());
            param.setProdNum(order.getProductNums());
            param.setCreateTime(order.getCreateTime());
            param.setSendType(SendType.WRITE_OFF.getValue());
            applicationContext.publishEvent(new SendMessageEvent(param));
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error(SendType.WRITE_OFF + "：消息推送失败！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTagNotify(NotifyTemplate notifyTemplate) {
        save(notifyTemplate);
        notifyTemplateTagMapper.insertBatch(notifyTemplate);
    }

    @Override
    public IPage<NotifyTemplate> pageTagNotify(PageParam<NotifyTemplate> page) {
        List<NotifyTemplate> notifyTemplates = notifyTemplateMapper.pageTagNotify(new PageAdapter(page));
        for (NotifyTemplate notifyTemplate : notifyTemplates) {
            List<UserTagParam> tagParams = notifyTemplate.getTagParams();
            // 拼接字符串
            StringBuilder tagNames = new StringBuilder(100);
            for (UserTagParam tagParam : tagParams) {
                tagNames.append(tagParam.getTagName()).append(StrUtil.COMMA);
            }
            tagNames.subSequence(0, Math.min(tagNames.length() - 1, 100));
            if (tagNames.lastIndexOf(",") == tagNames.length() - 1) {
                tagNames.deleteCharAt(tagNames.length() - 1);
            }
            notifyTemplate.setApp(true);
            notifyTemplate.setTemplateCode(tagNames.toString());
        }
        page.setRecords(notifyTemplates);
        page.setTotal(notifyTemplateMapper.countTagNotify());
        return page;
    }


    /**
     * 消息推送-用户已经确认收货、买家已退货
     * @param order 订单信息
     * @param sendType 类型
     */
    @Override
    @Async
    public void sendNotifyByUserRefundDelivery(Order order, SendType sendType) {
        if(Objects.equals(order.getShopId(),Constant.PLATFORM_SHOP_ID)){
            return;
        }
        NotifyTemplateParam param = new NotifyTemplateParam();
        ShopDetail shopDetail = shopDetailService.getById(order.getShopId());
        User userDb = userService.getById(order.getUserId());
        try {
            User user = new User();
            user.setUserId(shopDetail.getUserId());
            user.setUserMobile(shopDetail.getReceiveMobile());
            user.setNickName(userDb.getNickName());
            param.setUser(user);
            param.setRemark(order.getRemarks());
            param.setProdName(order.getProdName());
            param.setShopId(order.getShopId());
            param.setOrderNumber(order.getOrderNumber());
            param.setSendType(sendType.getValue());
            applicationContext.publishEvent(new SendMessageEvent(param));
        }catch (Exception e){
            log.error(e.getMessage());
            log.error(sendType.getDesc() + "：消息推送失败！");
        }
    }


}
